



                                ACME

        ...the ACME Crossassembler for Multiple Environments


                            Release 0.05

                         - free  software -

                        (C) 1998  Marco Baye




  1. Copyright

ACME - a crossassembler for producing 6502/65c02/65816 code.
Copyright (C) 1998 Marco Baye
Icon designed by Wanja "Brix" Gayk

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA




  2. Introduction

ACME is a crossassembler for the 65xx range of processors. It knows
about the standard 6502, the 65c02 and the 65816. Support for some
illegal opcodes of the 6510 processor (a 6502-variant that is used in
the C=64) is planned, maybe even support for the Z80 processor.

This text only describes the basic functions that are independent of
the platform used. There should be another help file in this archive
that outlines the platform specific features.

ACME was initially developed under RISC OS. Currently there are
platform-specific versions available for RISC OS, DOS, AmigaOS and
Linux. In addition to that, the sources should be ready to compile on
most other UNIX systems. In the future there will hopefully also be a
version that runs on the C64/128.
If you want to port ACME to another platform, please inform me so that
I can add your version to the ones already present on the ACME
homepage. As the sources are released under the GNU General Public
License, you are not forced to do this; but it would help to make ACME
available to other users.
The same goes for any changes or enhancements to the sources: Please
send me a copy so that the changes can be incorporated into the next
"official" release on the ACME home page.




  3. Use

Write a text file containing assembler source code for one of the
processors ACME knows about. Start ACME by typing

acme <sourcefile>

ACME will parse the file and report any errors. An output file will
only be generated if there were no errors and if the source file
contains the relevant directive.




  4. Syntax

A text line may contain several assembler statements, separated by
colons (":").
A semicolon outside of quotes marks the remainder of the line as a
comment, which is always skipped.
Assembler mnemonics and pseudo opcodes are case insensitive, so
whether you write "LDA" or "lda" or "LdA" does not make a difference.
Arithmetic operators like MOD, XOR, LSL must be written in UPPER
CASE; this rule simply serves to make them stand out.
Label names are case sensitive, so "label" and "Label" are two
different things !
Label names may consist of these characters: "a" to "z", "A" to "Z",
"0" to "9", the underscore character "_" and all characters with the
top bit set (= with values beyond 127). The first character must not
be a digit though !
Any such string that is not recognized as a valid assembler mnemonic
is treated as a global label.
Any string preceded by a dot (".") is treated as a local label (the
scope of which is set by the pseudo opcode "!zone").
Any string preceded by an exclamation mark ("!") is treated as a
pseudo opcode, these are assembler directives for special functions.


  !!! large important part of documentation is still missing here !!!


The program counter is set like this:

;--- example code fragment, start ---

*= $c000

;--- example code fragment, end ---

You can use offset assembly by just redefining the program counter. To
get back the "original" PC, just do this:

;--- example code fragment, start ---

*

;--- example code fragment, end ---


  !!! large important part of documentation is still missing here !!!




  5. Pseudo Opcodes

This is a list of all the pseudo opcodes currently implemented
(further ones are planned). Stuff in square brackets is optional,
stuff followed by "*" may be given more than once.



    !al

Switch to long accumulator.
Only allowed when producing code for the 65816 CPU.



    !rl

Switch to long index registers.
Only allowed when producing code for the 65816 CPU.



    !as

Switch to short accumulator.
Only needed when producing code for the 65816 CPU.



    !rs

Switch to short index registers.
Only needed when producing code for the 65816 CPU.



    !align <and_value>, <equal_value> [, <fill_value>]

ACME outputs <fill_value> until "PC AND <and_value>" equals
<equal_value>. If no <fill_value> is given, ACME uses $ea (the NOP
command of the 6502 CPU).
This pseudo opcode can be useful for eliminating the original 6502's
JMP()-Bug, for example (use "!align 1, 0" just before declaring
your pointer location).

;--- example code fragment, start ---

!align 255, 0 ; align code to page border for speed increase

;--- example code fragment, end ---



    !binary "filename" [, size]
    !bin    "filename" [, size]
    !binary <filename> [, size]
    !bin    <filename> [, size]

ACME inserts the given binary file directly into the output file. If a
size value is given, it is used: If the file is longer, only <size>
bytes are read; if it is shorter, ACME will use padding until <size>
is reached.
WARNING to the C64 coders - the file will be inserted from its start,
no "load address" will be stripped. I think I will add a possibility
to change this...

;--- example code fragment, start ---

!bin <Own/menudata.b>        ; insert file from ACME library
!bin "tables/asc2pet.b", 256 ; insert file from current directory

;--- example code fragment, end ---



    !cbm

Switch to Commodore mode. This pseudo opcode makes "!text" behave like
"!pet" instead of behaving like "!raw". Further functionality may be
added later.



    !cpu <cpu_keyword>

Select the processor to produce output for. Currently valid keywords
are "6502", "65c02" and "65816".

;--- example code fragment, start ---

!cpu 65816 ; allow new commands

;--- example code fragment, end ---



    !end

End processing the current source file. The only purpose of this
pseudo opcode is that you can add explanatory text inside your source
file without having to comment out every single line of it.

;--- example code fragment, start ---

rts
!end
Though this text isn't preceded by a semicolon, it is treated as if it
were a comment. In fact, ACME doesn't even parse this anymore - the
file gets closed when "!end" is reached.

;--- example code fragment, end ---



    !fill <amount> [, <value>]
    !fi   <amount> [, <value>]

Output <amount> bytes of <value>. If <value> is omitted, a default
value is used.

;--- example code fragment, start ---

!fi 256, $ff ; reserve space for 256 bytes

;--- example code fragment, end ---



    !zone [zone title]
    !zn   [zone title]

Switch to new zone of local variables. The title does not have any
real meaning, but as it will be displayed if errors occur in this
zone, it might speed up finding errors. Each zone ends where the next
one begins. If you want to nest zones, you have to use "!subzone"
(see below).

;--- example code fragment, start ---

!zn LinkedList_Init

;--- example code fragment, end ---



    !subzone [zone title] { <lines> }
    !sz      [zone title] { <lines> }

Switch to new zone of local variables. The title does not have any
real meaning, but as it will be displayed if errors occur in this
zone, it might speed up finding errors. Using this pseudo opcode,
you can nest zones of local labels.

;--- example code fragment, start ---

!subzone LinkedList {
    ; imagine some code here... :)
    !zone LinkedList_Init
    ; imagine some code here... :)
    !subzone LinkedList_Body {
        !zone LinkedList_
        ; imagine some code here... :)
    }
    !zone LinkedList_End
    ; imagine some code here... :)
}

;--- example code fragment, end ---



    !sl "filename"

Save all the global labels to the given file after the assembly is
finished. This table could be loaded during another assembly session
using the "!source" pseudo opcode.

;--- example code fragment, start ---

!sl "Labels.a"

;--- example code fragment, end ---



    !source "filename"
    !src    "filename"
    !source <filename>
    !src    <filename>

Include the given sourcecode file. After having processed the new
file, ACME continues processing the old one.

;--- example code fragment, start ---

!src <6502/std.a> ; include standard file for 6502 CPU from ACME library
!src "Macros.a"   ; include macro definitions from current directory

;--- example code fragment, end ---



    !to "filename"

Defines the output filename. Currently ACME produces output files in
Commodore format (which means that the first two bytes are the load
address).

;--- example code fragment, start ---

!to "program.o"

;--- example code fragment, end ---



    !byte <value> [, <value>]*
    !by   <value> [, <value>]*

Insert byte values.

;--- example code fragment, start ---

!by 14, $3d, %0110, &304, *, "c", label
!by 3 - 4, label1 EOR label2, 2 ^ tz, (3+4)*7

;--- example code fragment, end ---



    !word <value> [, <value>]*
    !wo   <value> [, <value>]*

Insert 16-bit values.

;--- example code fragment, start ---

!wo 14, $4f35, %100101010010110, &36304, *, "c"
!wo 3000 - 4, label1 AND label2, 2 ^ tz, (3+4)*70, l1 & .j2

;--- example code fragment, end ---



    !text <string or value> [, <string or value>]*
    !tx   <string or value> [, <string or value>]*

Output the given string using the standard conversion. At the
moment this is either PetSCII conversion (if you have used the "!cbm"
pseudo opcode) or no conversion (if you have *not* used the "!cbm"
pseudo opcode).

;--- example code fragment, start ---

!tx "Loading...", Char_NewLine, "Filename:", 0

;--- example code fragment, end ---



    !pet <string or value> [, <string or value>]*

Output the given string after converting it to "PetSCII" code (This
means to exchange the upper- and lowercase characters. Useful for C64
programs).

;--- example code fragment, start ---

!pet "Loading...", Char_NewLine, "Filename:", 0

;--- example code fragment, end ---



    !raw <string or value> [, <string or value>]*

Output the given string without any conversion at all.

;--- example code fragment, start ---

!raw "Loading...", Char_NewLine, "Filename:", 0

;--- example code fragment, end ---



    !scr <string or value> [, <string or value>]*

Output the given string after converting it to C64 screencode.

;--- example code fragment, start ---

!scr "Loading...", Char_NewLine, "Filename:", 0

;--- example code fragment, end ---



    !scrxor <exor_value>, <string or value> [, <string or value>]*

Output the given string after converting it to C64 screencode and
having exclusive-ORd each character with the given value (Useful for
C64 programs when inverse video is needed, or EBCM mode, etc.).

;--- example code fragment, start ---

!scrxor $80, "Loading..."

;--- example code fragment, end ---



  !if <condition> { <lines> } [ else { <lines> } ]

Conditional assembly. If the condition is true, the first block of
lines will be parsed; if it isn't, the second block will be used
instead (if present).

;--- example code fragment, start ---

!text "Black", 0
!if country = uk {
    !text "Grey"
} else {
    !text "Gray"
}
!byte 0
!text "White", 0

!if debug { lda #"z":jsr char_output }

;--- example code fragment, end ---



  !set <label> = <value>

Assign given value to label even if the label had a different value
before. Needed for loop counters, for example (see below).



  !do [<until/while condition>] { <lines> } [<until/while condition>]

Looping assembly. The block of lines can pe parsed several times,
depending on the given condition(s). Conditions may be placed before
or after the block (or even at both places). A condition may begin
with either one of the keywords "until" or "while.

;--- example code fragment, start ---

!set a = 0
!do while loop_flag = TRUE {
    lda #a
    sta label
    !set a = a + 1
} until a > 6

!do while * < $c000 { nop }

;--- example code fragment, end ---



  !macro <title> [<label> [, <label>]*] { <lines> }

Macro definition. If the title's first character is a dot ("."),
the macro will be local (though why anyone could want this is beyond
me). Normally, all parameter labels should be local (first character
a dot), as different macro calls will almost for sure have different
parameters.

;--- example code fragment, start ---

; far branches
!macro bne .target {
    bne * + 5
    jmp .target
}

; increase 16-bit counters
!macro dinc .target {
    inc .target
    bne .j          ;"bne * + 5" wouldn't work with zeropage locations
    inc .target + 1
.j
}

!macro ldax .target {
    lda .target
    ldx .target + 1
}

!macro stax .target {
    sta .target
    stx .target + 1
}

;--- example code fragment, end ---



  +<macro title> [<value> [, <value>]]

Macro call.

;--- example code fragment, start ---

inc label
bne mark    ; "near" branch
inc label2
+bne mark2  ; "far" branch

inc $fa     ; increase  8-bit counter
+dinc $fb   ; increase 16-bit counter

ldy label   ; get byte
+ldax label2; get two bytes

; using macro calls in a macro definition
!macro cp16 .source, .target {
    +ldax .source
    +stax .target
}

;--- example code fragment, end ---




  6. Typecasting

  !!! large important part of documentation is still missing here !!!
  (stuff concerning "+1", "+2", "+3" postfixes etc.)




  7. Arithmetic / logic

This is a list of the operators currently known by ACME:

priority    example     meaning                 alternative name
---------------------------------------------------------------------
      13        ! v     Complement of           NOT
      12     v  ^ w     To the power of
      11        - v     Negate
      10     v  * w     Multiply
      10     v  / w     Integer-Divide          DIV
      10     v  % w     Remainder of DIV        MOD
       9     v  + w     Add
       9     v  - w     Subtract
       8     v << w     Shift left              LSL, ASL
       8     v >> w     Logical shift right     LSR
       7        < v     Lowbyte of
       7        > v     Highbyte of
       7        ^ v     Bankbyte of
       6     v <= w     Lower or equal
       6     v <  w     Lower than
       6     v >= w     Higher or equal
       6     v >  w     Higher than
       5     v != w     Not equal               <>,  ><
       4     v  = w     Equal
       3     v  & w     Bit-wise AND            AND
       2                Bit-wise exclusive OR   EOR, XOR
       1     v  | w     Bit-wise OR             OR

Operations with higher priority are done first. Of course you can
change this using parentheses. If you prefer the alternative names
over the shorthand characters, don't forget that they must be written
in capital letters.
  Numbers are accepted in different formats; for example:
    *           the value of the program counter
    9260        decimal     (no prefix)
    $1a8e       hexadecimal (prefixed "$")
    0x8b4f      hexadecimal (prefixed "0x")
    &1054       octal       (prefixed "&")
    %10010      binary      (prefixed "%")
    "r"         character   (enclosed in double quotes)
  The value of the character can be altered by choosing a conversion
table, for example to PetSCII or C64-Screencode.
  Note that the value of the program counter is always the value that
was valid at the start of the current statement, so...

;--- example code fragment, start ---

!word *, *, *, *

;--- example code fragment, end ---

...will produce the *same* value four times.




  8. Portability

Though the source code does not exactly look like it *g*, ACME was
written with portability in mind: Some of its limitations were
included on purpose, just to allow a C64/128 version. To successfully
assemble multi-file source codes from other platforms, the filenames
have to be altered as little as possible. Please name all your files
that may be distributed in a sensible way, for example by limiting
their filenames to 8+3 format. I really hate this stupid
will-it-ever-die DOS convention, but using it is the only way to
ensure portability of files.
Please use "a" as the filename extension of ACME source code files.

All file names used in source files have to be in UNIX style, ACME
will convert them to the current host platform style if needed.

Another (but minor) problem with portability is the different
character tables used on different systems. As all ACME keywords only
use 7-bit ASCII, the assembler will work on any system that uses a
superset of this character table (ANSI, ISO 8859, ASCII, etc.).
Labelnames with top-bit-set characters may look strange on a
different platform, but ACME will work nevertheless.




  9. Misc


    9.1. "BIT"

Though the opcode "BIT" cannot be used with implicit addressing
mode (= that means without any parameter), ACME does accept it. In
that case, ACME outputs the opcode for 16-bit absolute addressing
without sending any address afterwards. This does come in handy when
you want to skip the following 2-byte command.

;--- example code fragment, start ---

label0  ldx #01; call routine with x=1
        bit
label1  ldx #02; call routine with x=2
        bit
label2  ldx #03; call routine with x=3
        ;...here follows a routine that takes X as an argument...

;--- example code fragment, end ---

When the processor executes one of the BIT commands, it uses the
following LDX command as the argument and skips it this way. This
trick is used extensively in the C128 ROM, for example.


    9.2. "%"

When using binary values, you can substitute the characters "0" and
"1" by "." and "#" respectively. This way the values are much more
readable.


    9.3 "JMP", "JSR", "JML" and "JSL"

In addition to the commands JMP and JSR, the 65816 processor also
knows JML and JSL, which are JMP and JSR using new (long) addressing
modes. ACME also accepts the new addressing modes when using the old
mnemonics JMP and JSR, but the old addressing mode cannot be used
with the new mnemonics JML and JSL.



 10. Contacting the author

The newest version of ACME can be found at the ACME homepage:
http://home.pages.de/~mac_bacon/acme/

If you want to report a bug or make a suggestion, then simply drop
me an email:
mailto:Marco.Baye@tu-clausthal.de

